using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Imagination;

namespace Imagination.Display
{
    public class Camera
    {
        private Thing   thingTarget = null;
        private Vector3 followOffset;
        private Matrix  view;
        private Matrix  projection;
        private Vector3 position;
        private Vector3 target;

        private float   fieldOfView;
        private float   aspectRatio;
        private float   nearPlane;
        private float   farPlane;

        private BoundingFrustum frustum;

        public Camera(GraphicsDevice device)
        {
            this.target = new Vector3(0, 0, -50f);
            //this.fieldOfView = (float)(Math.PI / 4.0f);
            this.fieldOfView = MathHelper.ToRadians(45);
            UpdateAspectRatio(device);
            this.nearPlane = 1.0f;
            this.farPlane = 10000.0f;
        }

        public void UpdateAspectRatio(GraphicsDevice device)
        {
            this.aspectRatio = device.DisplayMode.Width / device.DisplayMode.Height;
        }

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        public Vector3 Target
        {
            get { return target; }
            set { target = value; }
        }

        public float FieldOfView
        {
            get { return fieldOfView; }
            set { fieldOfView = value; }
        }

        public float AspectRatio
        {
            get { return aspectRatio; }
            set { aspectRatio = value; }
        }

        public float NearPlane
        {
            get { return nearPlane; }
            set { nearPlane = value; }
        }

        public float FarPlane
        {
            get { return farPlane; }
            set { farPlane = value; }
        }

        public BoundingFrustum Frustum
        {
            get { return frustum; }
        }

        public void Follow(Thing thingToFollow, Vector3 offset)
        {
            thingTarget = thingToFollow;
            followOffset = offset;
        }

        public void StopFollowing()
        {
            thingTarget = null;
        }

        public void Refresh()
        {
            projection = Matrix.CreatePerspectiveFieldOfView(
                fieldOfView, aspectRatio, nearPlane, farPlane);
            
            if (thingTarget != null)
            {
                target = thingTarget.Position;
                position = target + followOffset;
            }
            view = Matrix.CreateLookAt(position, target, Vector3.Up);
            frustum = new BoundingFrustum(view * projection);
        }

        public void Update(GameTime gameTime)
        {
            Refresh();
        }

        public Matrix Projection
        {
            get { return projection; }
        }

        public Matrix View
        {
            get { return view; }
        }
    }
}
